package com.google.code.jtasks.manager;

import java.util.List;

import org.joda.time.DateTime;
import org.joda.time.ReadablePeriod;

import com.google.code.jtasks.adapters.ITaskSystemAdapter;
import com.google.code.jtasks.connection.TaskRepoConnectionSettings;
import com.google.code.jtasks.manager.cache.IQueryCache;
import com.google.code.jtasks.manager.cache.TaskEnumsRegistry;
import com.google.code.jtasks.model.IMappedTask;
import com.google.code.jtasks.query.TaskQuery;
import com.google.code.jtasks.query.TaskQueryResult;

/**
 * The {@link ITaskRepoManager} implementation, used by {@link TaskRepoManagerFactoryImpl}.
 */
public final class TaskRepoManagerImpl implements ITaskRepoManager
{
	private final TaskRepoConnectionSettings connection;
	private final TaskEnumsRegistry registry;
	private final IQueryCache cache;

	/**
	 * Constructs a new {@link TaskRepoManagerImpl} instance.
	 * 
	 * @param connection
	 *            the {@link TaskRepoConnectionSettings} for the task repository that this
	 *            {@link TaskRepoManagerImpl} should interact with
	 * @param registry
	 *            the {@link TaskEnumsRegistry} for the task repository that this {@link TaskRepoManagerImpl}
	 *            should interact with
	 * @param cache
	 *            the application {@link IQueryCache} to use
	 */
	public TaskRepoManagerImpl(TaskRepoConnectionSettings connection, TaskEnumsRegistry registry,
			IQueryCache cache)
	{
		this.connection = connection;
		this.registry = registry;
		this.cache = cache;
	}

	/**
	 * @see com.google.code.jtasks.manager.ITaskRepoManager#getEnumsRegistry()
	 */
	@Override
	public TaskEnumsRegistry getEnumsRegistry()
	{
		return registry;
	}

	/**
	 * @see com.google.code.jtasks.manager.ITaskRepoManager#createQuery()
	 */
	@Override
	public TaskQuery createQuery()
	{
		return new TaskQuery(connection);
	}

	/**
	 * @see com.google.code.jtasks.manager.ITaskRepoManager#query(com.google.code.jtasks.query.TaskQuery)
	 */
	@Override
	public TaskQueryResult query(TaskQuery query)
	{
		return query(query, null);
	}

	/**
	 * @see com.google.code.jtasks.manager.ITaskRepoManager#query(com.google.code.jtasks.query.TaskQuery,
	 *      org.joda.time.ReadablePeriod)
	 */
	@Override
	public TaskQueryResult query(TaskQuery query, ReadablePeriod maxResultAge)
	{
		// First, try to retrieve the result from the cache
		DateTime oldestAllowedResult = new DateTime().minus(maxResultAge);
		TaskQueryResult cachedResult = cache.getQueryResult(query);
		if (cachedResult != null
				&& (maxResultAge == null || cachedResult.getTimestamp().compareTo(oldestAllowedResult) >= 0))
			return cachedResult;

		// Cached result wasn't found or was too stale. Run the query.
		ITaskSystemAdapter adapter = connection.getAdapter();
		TaskQueryResult result = adapter.runQuery(query);

		// Cache the result and register any enums found in it
		cache.putCachedResult(result);
		registerEnums(registry, result.getTasks());

		return result;
	}

	/**
	 * Registers all of the enumerated values in the specified {@link IMappedTask}s with the specified
	 * {@link TaskEnumsRegistry}.
	 * 
	 * @param registry
	 *            the {@link TaskEnumsRegistry} to register the values with
	 * @param tasks
	 *            the {@link IMappedTask} to pull register-able values out of
	 */
	private static void registerEnums(TaskEnumsRegistry registry, List<IMappedTask> tasks)
	{
		for (IMappedTask task : tasks)
		{
			if (task.getPriority() != null)
				registry.register(task.getPriority());
			if (task.getResolution() != null)
				registry.register(task.getResolution());
		}
	}
}
